#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netinet/in.h>

int port = 80;
char * proc_call = "./ep";


int main(int argc, char **argv)
{
	struct sockaddr_in 	s_addr, c_addr;
	socklen_t client_len;
	int server_fd, client_fd;
	pid_t pid;

	int reuse = 1;

    if (argc == 2) {
        port = atoi(argv[1]);
    }

	s_addr.sin_family = AF_INET;
	s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	s_addr.sin_port = htons(port);

	if ((server_fd = socket(s_addr.sin_family, SOCK_STREAM, 0)) < 0) {
		fprintf(stderr, "%s: socket create error: %s\n", argv[0], strerror(errno));
		exit(1);
	}

	if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
		fprintf(stderr, "%s: setsockopt SOL_SOCKET SO_REUSEADDR error: %s\n", argv[0], strerror(errno));
		exit(1);
	}

	if (bind(server_fd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0) {
		fprintf(stderr, "%s: bind port %d error: %s\n", argv[0], port, strerror(errno));
		exit(2);
	}

	if (listen(server_fd, 100) < 0) {
		fprintf(stderr, "%s: listen error: %s\n", argv[0], strerror(errno));
		exit(3);
	}

	printf("%s: listen %d\n", argv[0], port);
	signal(SIGCHLD, SIG_IGN);

	while (1) {
		client_len = sizeof(struct sockaddr);
		if ((client_fd = accept(server_fd, (struct sockaddr *)&c_addr, &client_len)) < 0) {
			fprintf(stderr, "%s: accept error: %s\n", argv[0], strerror(errno));
			usleep(1000*1000*5);
			continue;
		}
		pid = fork();
		if (pid < 0) {
			perror("fork error");
			usleep(1000*1000*5);
			continue;
		}
		else if (pid == 0)  // child
			goto __child;
		close(client_fd);
	}

	return 0;

#define max_paramet 100

	int n;
	char buff[1024*4];
	char screen[256];
	char request_line[1024];
	char request_file[256];
	char command[256];
	char *p = 0;
	char *pc[max_paramet] = {0};

__child: 	//Child process action
	if (dup2(client_fd, 1) < 0) {
		write(client_fd, "dup2 error\n", 11);
		goto __syserr;
	}
	memset(buff, 0, sizeof(buff));
	n = read(client_fd, buff, sizeof(buff)); //Recv http Request head
	if (buff[sizeof(buff)-1] != 0) {
		_exit(2);
	}

#ifdef SHOW_REQUEST
 	//shuw the head request
	fprintf(stderr, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
	fprintf(stderr, "%s\n", buff);
	fprintf(stderr, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
#endif

	p = strstr(buff, "GET /"); //Find  request GET
	if (p == 0) _exit(1);  	//No such GET and _exit
	sscanf(p, "GET /%[^ ]", request_line); //Get the request line
	if (request_line[0] == 0) {  	//	If GET request is null,	use index.html default
		snprintf(request_file, sizeof(request_file), "index.html");
		n = snprintf(screen, sizeof(screen), "Request file  %s <default>\n", request_file);
		write(2, screen, n);
		pc[0] =	proc_call;
		pc[1] =	request_file;
		pc[2] =	0;
	} else {
		if (strncmp("shell=", request_line, 6) == 0) {
			p = request_line + 6;
			if (*p == 0) {
				printf("Shell is null\n");
				_exit(1);
			}
			snprintf(command, sizeof(command), "%s", p);
			p = command;  // p -> command
			if ((*p < 'A' || *p > 'Z') && (*p < 'a' || *p > 'z')) {
				printf("syntax error\n");
				goto __syserr;
			}
			n = snprintf(screen, sizeof(screen), "Request shell %s\n", p);
			write(2, screen, n);
			pc[0] = command;
			n = 1;
			while ((p = strstr(p, "%20")) && n < max_paramet - 1) {
				*p = 0;
				p+=3;
				if (*p == '%') continue;
				pc[n] = p;
				n++;
			}
			if (n == max_paramet - 1) {
				printf("paramet limit\n");
				goto __syserr;
			}
			pc[n] = 0;
			printf("Shell execute result . . .\n");
		}
		//... else if () //... more
		else {
			sscanf(request_line, "%[^ ]", request_file);
			n = snprintf(screen, sizeof(screen), "Request file  %s\n", request_file);
			write(2, screen, n);
			pc[0] =	proc_call;
			pc[1] =	request_file;
			pc[2] =	0;
		}
	}
	if (dup2(client_fd, 2) < 0) {
		write(client_fd, "dup2 error\n", 11);
		goto __syserr;
	}
	if (execvp(pc[0], &pc[0]) < 0) {
		write(client_fd, "exec error\n", 11);
		goto __syserr;
	}
__syserr:
	_exit(1);
}

